package ch.fusun.baron.property;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import ch.fusun.baron.data.AbstractDataProvider;
import ch.fusun.baron.data.DataListener;
import ch.fusun.baron.data.DataUpdate;
import ch.fusun.baron.property.api.PropertyService;

/**
 * Property Service
 */
public class PropertyServiceImpl extends AbstractDataProvider implements
		PropertyService {

	/**
	 * Map<Owned, Owner>
	 */
	private final Map<Object, Object> ownership = new HashMap<Object, Object>();

	@Override
	public DataUpdate createFullUpdate() {
		return new PropertyDataUpdate(ownership);
	}

	@Override
	public boolean isOwned(Object tile) {
		return ownership.containsKey(tile);
	}

	@Override
	public void setOwnership(Object owner, Object owned) {
		ownership.put(owned, owner);
		for (DataListener listener : getListeners()) {
			listener.dataChanged(new SetOwnerShipDataUpdate(owner, owned));
		}
	}

	@Override
	public Object getOwnership(Object tile) {
		return ownership.get(tile);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> getAllOwnerships(Object owner, Class<T> clazz) {
		List<T> result = new LinkedList<T>();
		for (Entry<Object, Object> element : ownership.entrySet()) {
			if (element.getValue().equals(owner)) {
				if (clazz.isInstance(element.getKey())) {
					result.add((T) element.getKey());
				}
			}
		}
		return result;
	}

	@Override
	public <S, T> Map<S, List<T>> getAllOwnerships(Class<S> ownerClass,
			Class<T> ownedClass) {
		Map<S, List<T>> result = new HashMap<S, List<T>>();
		for (Entry<Object, Object> element : ownership.entrySet()) {
			@SuppressWarnings("unchecked")
			S owner = (S) element.getValue();
			@SuppressWarnings("unchecked")
			T owned = (T) element.getKey();

			if (ownerClass.isInstance(owner) && ownedClass.isInstance(owned)) {
				if (result.get(ownerClass) == null) {
					result.put(owner, new LinkedList<T>());
				}
				result.get(owner).add(owned);
			}
		}
		return result;
	}
}
